﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Utils.States
{
    public class Transition
    {
        public delegate bool GCMethod();
        public delegate bool GCMethodCtx(StateMachineCtx ctx);
        public delegate void ActivityMethod();
        public delegate void ActivityMethodCtx(StateMachineCtx ctx);

        State from;
        State to;
        GCMethod guardCondition;
        GCMethodCtx guardConditionCtx;
        ActivityMethod activity;
        ActivityMethodCtx activityCtx;
        bool hasTrigger;
        StateMachineCtx ctx;

        public State From { get { return from; } }
        public State To { get { return to; } }
        public GCMethodCtx GuardConditionCtx { get { return guardConditionCtx; } }
        public GCMethod GuardCondition { get { return guardCondition; } }
        public ActivityMethod Activity { get { return activity; } }
        public ActivityMethodCtx ActivityCtx { get { return activityCtx; } }
        public EventHandler<EventArgs> Trigger
        {
            get
            {
                hasTrigger = true;
                ctx = new StateMachineCtx();
                return OnEvent;
            }
        }

        public Transition(
            State from, State to,
            GCMethod guardCondition, GCMethodCtx guardConditionCtx)
        {
            this.from = from;
            this.to = to;
            this.guardCondition = guardCondition;
            this.guardConditionCtx = guardConditionCtx;
        }

        public Transition TF(ActivityMethod activity)
        {
            this.activity = activity;
            return this;
        }

        public Transition TF(ActivityMethodCtx activity)
        {
            this.activityCtx = activity;
            return this;
        }

        public bool CheckGuardConditions(StateMachineCtx ctx)
        {
            return (GuardCondition == null || GuardCondition())
                    && (GuardConditionCtx == null || GuardConditionCtx(ctx));
        }

        public void OnEvent(object sender, EventArgs e)
        {
            if (from.Active)
            {
                ctx.EventSender = sender;

                if (CheckGuardConditions(ctx))
                {
                    from.EventTransition(this, new EventTransitionArgs(this, ctx));
                }

                ctx.Clear();
            }
        }

        public bool HasTrigger()
        {
            return hasTrigger;
        }
    }
}
